#ifndef __DKGL_MOVABLE_H__
#define __DKGL_MOVABLE_H__

#include "dkglPreRequest.h"
#include "dkglString.h"
#include <boost/shared_ptr.hpp>
#include <list>

namespace DKGL
{
    class Movable;
    class Vector3;
    class Drawable;

    namespace Primitive
    {
        class Axes;
    }// namespace Primitive

    typedef boost::shared_ptr<Movable> MovablePtr;

    /**
     * This Class is rewriten from BaseObject
     */
    class Movable// : public HeapTracked
    {
    public:

        Movable(const String& name);

        virtual ~Movable();

        void rotate(float degree, const Vector3& axis,TRANS_SPACE space);
        void rotate(float degree, float x, float y, float z,TRANS_SPACE space);
	
        void translate(const Vector3& axis, TRANS_SPACE space);
	    void translate(float x, float y, float z, TRANS_SPACE space);
	    
        void scale(const Vector3& s);
        void scale(float x, float y, float z);
	
        // Logically movement
	    void moveForward(float dist);
	    
        void moveRight(float dist);
	    
        void moveUp(float dist);
	    
        void roll(float degree);
	    
        void yaw(float degree);
	    
        void pitch(float degree);

		/**
		 * Look at (x, y, z)
		 * http://www.opengl.org/sdk/docs/man/xhtml/gluLookAt.xml
		 */
		void lookAt(float x, float y, float z);

        void setPosition(const Vector3& position);
        void setPosition(float x, float y, float z);
	    
        Vector3 getPosition() const;
	    
        Vector3 getWorldPosition() const;

        void addChild(MovablePtr);

        inline void setParent(Movable* parent)
        {
            _parent = parent;
        }

        MovablePtr removeChild(const String& name);

        MovablePtr getChild(const String&);

        //void addRenderable()

        void updateTransform();

        void getParentTransformation(float* matrix) const;
	    
        void getParentRotationPart(float*) const;

        const String& getName(void) const;

        void showAxes(bool b = true);

        inline void addDrawable(Drawable* drawable)
        {
            _drawable = drawable;
        }

    protected:

        // object name
        String  _name;
        
        // record child-parent relation-ship
        //float   _localMatrix[16];

		Quaternion	_orientation;

		Vector3		_translation;

        //cached global matrix
        float   _globalMatrixCache[16];

        Movable* _parent;

        Primitive::Axes*   _axes;


        bool    _dirty;

        // children list
        typedef std::list<MovablePtr>       ChildList;
        typedef ChildList::iterator         ChildListIter;
        typedef ChildList::const_iterator   ChildListConstIter;

        ChildList   _childList;

        virtual void _transformation();

        void _updateChildrenTransform();

        Drawable*   _drawable;

    private:

        Movable();

    };
}// namespace

#endif